package com.example.easybuy.service.impl;

import com.example.easybuy.entity.Product;
import com.example.easybuy.mappers.ProductMapper;
import com.example.easybuy.repository.ProductEsRepository;
import com.example.easybuy.service.ProductService;
import com.example.easybuy.util.AjaxResult;
import com.example.easybuy.util.SftpUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jcraft.jsch.SftpException;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper mapper;
    @Autowired
    private ElasticsearchRestTemplate template;
    @Autowired
    private ProductEsRepository repository;

    @Override
    public PageInfo<Product> byPage(Map<String, Object> map) {
        map.put("orderBy", "createTime desc");
        if (map.containsKey("pageNum") && map.containsKey("pageSize")) {
            PageHelper.startPage(map);
        }
        List<Product> list = mapper.byPage(map);
        return new PageInfo<>(list);
    }


    @Transactional(rollbackFor = {Exception.class})
    @Override
    public boolean delPro(Map<String, Object> map) throws Exception {
        try {
            boolean isDel = mapper.delPro(map) > 0;
            repository.deleteById(map.get("id").toString());
            return isDel;
        } catch (Exception e) {
            throw new Exception();
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public AjaxResult addPro(Map<String, Object> map, MultipartFile fileItem) throws Exception {
        String newFileName = "";
        if (fileItem != null && !fileItem.getOriginalFilename().equals("")) {
            if (fileItem.getSize() > 5 * 1024 * 1024) {
                return AjaxResult.error().add("msg", "文件大小不能超过5MB");
            }
            String[] suffixs = {".png", ".jpg", ".txt"};
            String suffix = fileItem.getOriginalFilename().substring(fileItem.getOriginalFilename().lastIndexOf("."));
            boolean isOk = false;
            for (String s : suffixs) {
                if (s.equals(suffix)) {
                    isOk = true;
                    break;
                }
            }
            if (!isOk) {
//                return false;
                return AjaxResult.error().add("msg", "文件格式不正确");
            }
            newFileName = UUID.randomUUID() + suffix;
            SftpUtil sftp = new SftpUtil("sanshi", "123456", "192.168.126.132", 22);
            //登录
            sftp.login();
            InputStream is = null;
            try {
                is = fileItem.getInputStream();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            //输出到服务器特定目录
            try {
                sftp.upload("/home/sanshi/myfile/easyBuy/files", newFileName, is);
            } catch (SftpException e) {
                throw new RuntimeException(e);
            }
            //退出
            sftp.logout();
        }
        map.put("fileName", newFileName);
        try {
            boolean isAdd = mapper.addPro(map) > 0;
            int id = Integer.parseInt(map.get("id").toString());
            Map<String, Object> elasticSearch = new HashMap<>();
            elasticSearch.put("id", id);
            repository.save(mapper.getPro(map));
            return AjaxResult.success().add("status", isAdd);
        } catch (Exception e) {
            throw new Exception();
        }
    }


    @Transactional(rollbackFor = {Exception.class})
    @Override
    public AjaxResult updatePro(Map<String, Object> map, MultipartFile fileItem) throws Exception {
        String newFileName = "";
        if (fileItem != null && !fileItem.getOriginalFilename().equals("")) {
            if (fileItem.getSize() > 5 * 1024 * 1024) {
                return AjaxResult.error().add("msg", "文件大小不能超过5MB");
            }
            String[] suffixs = {".png", ".jpg", ".txt"};
            String suffix = fileItem.getOriginalFilename().substring(fileItem.getOriginalFilename().lastIndexOf("."));
            boolean isOk = false;
            for (String s : suffixs) {
                if (s.equals(suffix)) {
                    isOk = true;
                    break;
                }
            }
            if (!isOk) {
                return AjaxResult.error().add("msg", "文件格式不正确");
            }
            newFileName = UUID.randomUUID() + suffix;
            SftpUtil sftp = new SftpUtil("sanshi", "123456", "192.168.126.132", 22);
            //登录
            sftp.login();
            InputStream is = null;
            try {
                is = fileItem.getInputStream();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            //输出到服务器特定目录
            try {
                sftp.upload("/home/sanshi/myfile/easyBuy/files", newFileName, is);
            } catch (SftpException e) {
                throw new RuntimeException(e);
            }
            //退出
            sftp.logout();
        }
        map.put("fileName", newFileName);
        if (newFileName.isEmpty()) {
            map.remove("fileName");
        }
        map.remove("fileItem");
        ObjectMapper objectMapper = new ObjectMapper();
        Product product = objectMapper.convertValue(map, Product.class);
        try {
            boolean isUpdate = mapper.updatePro(map) > 0;
            repository.deleteById(map.get("id").toString());
            repository.save(product);
            return AjaxResult.success().add("status", isUpdate);
        } catch (Exception e) {
            throw new Exception();
        }
    }

    @Override
    public Product getPro(Map<String, Object> map) {
        return mapper.getPro(map);
    }

    @Override
    public PageInfo<Product> elByPage(Map<String, Object> map) {
        int pageNum = 1;
        int pageSize = 12;
        int categoryId = 0;
        String name = "";
        if (map.containsKey("name") && !map.get("name").toString().isEmpty()) {
            name = map.get("name").toString();
        }
        if (map.containsKey("pageNum") && !map.get("pageNum").toString().isEmpty()) {
            pageNum = Integer.parseInt(map.get("pageNum").toString());
        }
        if (map.containsKey("pageSize") && !map.get("pageSize").toString().isEmpty()) {
            pageSize = Integer.parseInt(map.get("pageSize").toString());
        }
        if (map.containsKey("categoryId") && !map.get("categoryId").toString().isEmpty()) {
            categoryId = Integer.parseInt(map.get("categoryId").toString());
        }

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        if (!name.isEmpty()) {
            boolQuery.must(QueryBuilders.matchQuery("name", name));
        }

        if (categoryId != 0) {
            BoolQueryBuilder categoryQuery = QueryBuilders.boolQuery();
            categoryQuery.should(QueryBuilders.termQuery("categoryLevel1Id", categoryId))
                    .should(QueryBuilders.termQuery("categoryLevel2Id", categoryId))
                    .should(QueryBuilders.termQuery("categoryLevel3Id", categoryId));
            boolQuery.must(categoryQuery);
        }

        nativeSearchQueryBuilder.withQuery(boolQuery)
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .withPageable(PageRequest.of(pageNum - 1, pageSize));

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name");
        highlightBuilder.preTags("<span style='color:red;'>");
        highlightBuilder.postTags("</span>");
        nativeSearchQueryBuilder.withHighlightBuilder(highlightBuilder);
        NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
        SearchHits<Product> searchHits = template.search(nativeSearchQuery, Product.class);
        List<Product> productList = new ArrayList<>();
        for (SearchHit<Product> hit : searchHits.getSearchHits()) {
            Map<String, List<String>> map1 = hit.getHighlightFields();
            Product product = hit.getContent();
            if (map1.containsKey("name") && !map1.get("name").isEmpty()) {
                product.setName(map1.get("name").get(0));
            }
            productList.add(product);
        }
        PageInfo<Product> pageInfo = new PageInfo<>();
        pageInfo.setList(productList);
        pageInfo.setTotal(searchHits.getTotalHits());
        pageInfo.setPages((int) (searchHits.getTotalHits() % pageSize == 0 ? searchHits.getTotalHits() / pageSize : searchHits.getTotalHits() / pageSize + 1));
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        return pageInfo;
    }
}
